package org.snail.common.xmlBean;

import lombok.extern.log4j.Log4j;
import org.apache.log4j.Logger;
import org.dom4j.*;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.*;
@Log4j
@Repository
@Service
public class XmlToDocHolder {
    private static final Logger LOGGER =  Logger.getLogger(XmlToDocHolder.class);

    public static Map<String, Object> personMap = new HashMap<>();
    private static Map rootDeptInfoMap = new HashMap();

    private static Long fileLastModified;

    /**
     * 修改xml属性要注意修改下面的map格式
     * {owner=7654, rootLevel=3, levelRules=, manager=7586, root=, deptId=22,
     * ruleMap=[{levelNum=3, currentMethod=DingGroupJob3}, {levelNum=4, currentMethod=DingGroupJob4}]}
     *
     * @return map 返回如上的map格式，注意字段的一致性
     */
    public Map xmlTransToBean() throws Exception {
        List deptIdRuleList = new ArrayList();
        List levelRuleList = new ArrayList();
        try{
            String filePath = "";
            try {
                filePath = this.getClass().getClassLoader().getResource("/").getPath() + "/" + "DingGroup.xml";
            } catch (NullPointerException e) {
                LOGGER.error("获取自定义部门配置失败！原因：找不到该路径！", e);
                throw new Exception("获取自定义部门配置失败！原因：找不到该路径！", e);
            }

            //判断文件是否修改
            boolean needUpdate = false;
            File file = new File(filePath);
            if(file.exists()) {
                if(null==fileLastModified) {
                    fileLastModified = file.lastModified();
                    needUpdate = true;
                } else if(fileLastModified < file.lastModified()) {
                    fileLastModified = file.lastModified();
                    needUpdate = true;
                }
            }

            //文件有修改才更新
            if(needUpdate) {
                rootDeptInfoMap.clear();
                SAXReader reader = new SAXReader();
                Document document = reader.read(file);
                //获取相对路径
                Element rootElement = document.getRootElement();// 获取根节点

                for (Iterator<?> iterator = rootElement.elementIterator(); iterator.hasNext(); ) {
                    Element element = (Element) iterator.next();
                    //获取第二层标签
                    personMap.put(element.getName(), element.getTextTrim());// 获取属性对象的值并插入map中，键名为gender
                    rootDeptInfoMap.put(element.getName(), element.getTextTrim());

                    //取得所有的二级(下一级)子节点
                    for (Iterator<?> iterator2 = element.elementIterator(); iterator2.hasNext(); ) {    //获取真正属性
                        Element element2 = (Element) iterator2.next();
                        if (null == element2) {
                            LOGGER.error("获取的属性名值为空！");
                            continue;   //没有子节点则直接返回
                        }

                        if (StringUtils.isEmpty(element2.getTextTrim())) {
                            int flag = 0;
                            Map levelRuleMapObj = new HashMap();
                            Map deptIdRuleMapObj = new HashMap();
                            for (Iterator<?> iterator3 = element2.elementIterator(); iterator3.hasNext(); ) {    //部门list属性
                                Element element3 = (Element) iterator3.next();
                                if (StringUtils.isEmpty(element3.getName()) || StringUtils.isEmpty(element3.getTextTrim())) {
                                    LOGGER.error("获取的属性名值为空！父标签名称："+element3.getParent().getName());
                                    continue;
                                }
                                if (element2.getName() == "levelRule") {
                                    levelRuleMapObj.put(element3.getName(), element3.getTextTrim());
                                    flag = 1;   //部门层级
                                } else if (element2.getName() == "deptIdRule") {
                                    deptIdRuleMapObj.put(element3.getName(), element3.getTextTrim());
                                    flag = 2;   //部门ID
                                }
                            }
                            if (flag == 1) {
                                levelRuleList.add(levelRuleMapObj);
                            } else if (flag == 2) {
                                deptIdRuleList.add(deptIdRuleMapObj);
                            }
                        }
                    }
                }
                rootDeptInfoMap.put("levelRules", levelRuleList);
                rootDeptInfoMap.put("deptIdRules", deptIdRuleList);
            }
        } catch(DocumentException e) {
            LOGGER.error("文档转换错误！", e);
        }
        return rootDeptInfoMap;
    }


    //将map转换成bean属性  map嵌套太多会导致
    private static <T> T toBean(Class<T> clazz, Map map) {
        T obj = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
            obj = clazz.newInstance(); // 创建 JavaBean 对象
            // 给 JavaBean 对象的属性赋值
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (map.containsKey(propertyName)) {
                    // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                    Object value = map.get(propertyName);
                    if ("".equals(value)) {
                        value = null;
                    }
                    Object[] args = new Object[1];
                    args[0] = value;
                    try {
                        descriptor.getWriteMethod().invoke(obj, args);
                    } catch (InvocationTargetException e) {
                        System.out.println("字段映射失败");
                    }
                }
            }
        } catch (IllegalAccessException e) {
            System.out.println("实例化 JavaBean 失败");
        } catch (IntrospectionException e) {
            System.out.println("分析类属性失败");
        } catch (IllegalArgumentException e) {
            System.out.println(e.getMessage());
            System.out.println("映射错误");
        } catch (InstantiationException e) {
            System.out.println("实例化 JavaBean 失败");
        }
        return (T) obj;
    }

}
